class Compiler {
    constructor(vm) {
        this.el = vm.$el;
        this.vm = vm;
        if (this.el) {
            this.compile(this.el);
        }
    }

    compile(el) {
        for (const node of el.childNodes) {
          
            if (node.childNodes.length) {
               
                this.compile(node);
            } else {
                if (this.isTextNode(node)) {
                    this.compileText(node)
                }
                if (this.isElementNode(node)) {
                   
                    this.compileElement(node)
                }
            }
        }
        // document.createDocumentFragment
    }

    /**
     * 处理指令节点
     * attributes
     * @param {Element} node 
     */
    compileElement(node) {
        for (const attrs of node.attributes) {
            const { name, value } = attrs;
            console.log('name',attrs);
            if (this.isDirective(name)) {
                const directive = name.substr(2);
                this.directive2agent(directive, node, value);
            }
        }
    }

    /**
     * 指令代理函数
     * @param {string} directive 
     * @param {Element} node 
     * @param {string} props 
     */
    directive2agent(directive, node, props) {
        console.log('directive',directive);
        const fn2atrrs = `${directive}Compile`;
        const fnCompile = this[fn2atrrs];
        if (fnCompile) {
            fnCompile.call(this, node, props);
        }
      
        if(directive.indexOf('on:')==0){
            this.onCompile(directive, node, props)
        }

    }

    onCompile(directive, node, props){
        console.log('onCompile','');
        const event = directive.substr(3);
        console.log('event',event,'props',props,this.$vm);
        let fn = this.vm.$options.methods[props];
        // node[`on`+event]=fn;
        node.addEventListener(event,fn);
    }

    /**
     * 
     * @param {Element} node 
     * @param {string} props 
     */
    textCompile(node, props) {
        const watcher = new Watcher(this.vm, props, function (vals) {
            node.innerText = node.innerText.replace(this.OldValues, vals);
        });
        node.innerText = watcher.OldValues;
    }

    /**
     * 
     * @param {Element} node 
     * @param {string} props 
     */
    htmlCompile(node, props) {
        const watcher = new Watcher(this.vm, props, function (vals) {
            node.innerText = node.innerText.replace(this.OldValues, vals);
        });
        node.innerHTML = watcher.OldValues;
    }

    /**
     * 
     * @param {Element} node 
     * @param {string} props 
     */
    modelCompile(node, props) {
        const watcher = new Watcher(this.vm, props, function (vals) {
            node.value = vals;
        });
        node.value = watcher.OldValues;
        // input事件就是最后输入到输入框的事件
        node.addEventListener("input", (e) => {
            if (!node.is_start_cn) {
                // this.eval2props(props, node.value);
                this.vm[props] = node.value;
            }
        });
        // compositionstart事件只有在输入中文时才会触发，触发事件在input事件之前
        node.addEventListener("compositionstart", (e) => {
            node.is_start_cn = true;
        });
        // compositionend表示结束中文输入时触发的事件，不管最后输入的是不是中文都会触发
        node.addEventListener("compositionend", (e) => {
            node.is_start_cn = false;
        });
    }

    /**
     * 处理插值表达式
     * nodeValue
     * textContent
     * @param {Element} node 
     */
    compileText(node) {
        let nodeValue = node.nodeValue.trim();
        if (nodeValue) {
            let regexp = /\{\{([\w.\s]+)\}\}/g;
            const list2match = nodeValue.match(regexp) || [];

            for (const template of list2match) {
                regexp = /\{\{([\w.\s]+)\}\}/g; // 深坑，勿踩
                const is_success = regexp.test(template);
                const NewVals = new Watcher(this.vm, RegExp.$1.trim(), function (vals) {
                    node.nodeValue = node.nodeValue.replace(this.OldValues, vals);
                });
                nodeValue = nodeValue.replace(template, NewVals.OldValues);
            }

            node.nodeValue = nodeValue;
        }
    }

    /**
     * 获取数据升级版函数
     * 后续参考vue-cli实现方式重写,定义与utils.js
     * this.vm[key]
     * 获取多层级数据
     * @param {string} attrs 
     */
    valueSolve(attrs = "") {
        const list2str = attrs.split('.');
        let NewVals = this.vm;
        for (const key of list2str || []) {
            const transit = NewVals[key];
            NewVals = transit ? transit : "";
        }
        return NewVals;
    }

    /**
     * 
     * @param {string} attrs 
     * @param {any} value 
     */
    eval2props(attrs, value) {
        // const fn2with = new Function('data', `with (data) { ${attrs} = ${value} }`);
        // fn2with(this.vm);

        const list2str = attrs.split('.');
        let NewVals = this.vm;
        for (const key of list2str || []) {
            const transit = NewVals[key];
            NewVals = transit ? transit : "";
        }
        if (NewVals) NewVals = value;
        console.log(NewVals);
    }

    /**
     * 
     * @param {string} attrs 
     */
    isDirective(attrs = '') {
        return attrs.startsWith('v-');
    }

    /**
     * 文本节点
     * nodeType:3
     * textContent
     * @param {Element} node 
     */
    isTextNode(node) {
        return 3 === node.nodeType;
    }

    /**
     * 元素节点
     * nodeType:1
     * textContent
     * @param {Element} node 
     */
    isElementNode(node) {
        return 1 === node.nodeType;
    }
}